home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / Development / General / GCC 1.37.1r15 / Machines / out-i386.c < prev    next >
Text File  |  1990-03-14  |  34KB  |  1,375 lines

  1. /* Subroutines for insn-output.c for Intel 80386.
  2.    Copyright (C) 1988 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU CC.
  5.  
  6. GNU CC is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU CC is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU CC; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #ifndef FILE
  21. #include <stdio.h>
  22. #endif
  23.  
  24. #define FP_TOP (gen_rtx(REG, DFmode, FIRST_FLOAT_REG))
  25.  
  26. #define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx))
  27. #define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
  28.  
  29. #define RET return ""
  30.  
  31. /* #define RETCOM(X) fprintf (asm_out_file, "%sX fp_pop_level=%d\n", \
  32.                COMMENT_BEGIN, fp_pop_level); RET */
  33. #define RETCOM(X) return ""
  34.  
  35. #define POP_ONE_FP    \
  36.   { /* fp_pop_level--; */    \
  37.     fprintf (asm_out_file, "\tfstp %sst (0)\n", RP); }
  38.  
  39. extern FILE *asm_out_file;
  40. static char *singlemove_string ();
  41. static void output_movf ();
  42. static void replace_float_constant ();
  43. static int mentions_fp_top ();
  44. static int call_top_dead_p ();
  45. static int fp_top_dead_p1 ();
  46. static rtx via_memory ();
  47. static void output_asm_insn_double_reg_op ();
  48.  
  49. /* All output functions must increment or decrement this to indicate
  50.    the net number of pops or pushes which they perform.  Note that it won't
  51.    necessarily balance with the optimize running, since we might have
  52.    two different calls with the same pop shared by cross jumping.
  53.    However on optimize the reg dead heuristic seems to work.  */
  54.  
  55. int fp_pop_level = 0;
  56.  
  57. static char *hi_reg_name[] = HI_REGISTER_NAMES;
  58. static char *qi_reg_name[] = QI_REGISTER_NAMES;
  59.  
  60. /* for fabs, fch, .. where the argument operand[1] must first be moved to
  61.   constraints  "=fm" "0" */
  62.  
  63. #define FP_CALL1(op)  \
  64.   { if (FP_REG_P (operands[0]))        \
  65.       return op;            \
  66.     output_movf (FP_TOP, operands[1]);    \
  67.     output_asm_insn (op, operands);    \
  68.     /* fp_pop_level--; */        \
  69.     return "fstp%z0 %0"; }
  70.  
  71. /* handle case of call where op0/op1 is "=mf" and opn is "mrf"
  72.    eg. fadd */
  73. #define FP_CALL(op, rev, n)  \
  74.   return fp_call_internal (op, rev, n, operands, insn);
  75.  
  76. static char *
  77. fp_call_internal (op, rev, n, operands, insn)
  78.      char *op;
  79.      char *rev;
  80.      int n;
  81.      rtx *operands;
  82.      rtx insn;
  83. {
  84.   if (!FP_REG_P (operands[0]))
  85.     {
  86.       /* Here destination is in memory
  87.      and source is in the fp stack.  */
  88.       output_movf (FP_TOP, operands[0]);
  89.       output_asm_insn_double_reg_op (op, rev, insn);
  90.       return "fstp%z0 %0";
  91.     }
  92.  
  93.   if (FP_REG_P (operands[n]))
  94.     {
  95.       rtx temp = operands[1];
  96.       char *tem1 = op;
  97.       operands[1] = operands[n];
  98.       op = rev;
  99.       operands[n] = temp;
  100.       rev = tem1;
  101.     }
  102.  
  103.   if (REG_P (operands[n]))
  104.     {
  105.       rtx xops[2];
  106.       via_memory (operands[n]);
  107.       operands[n] = AT_SP (GET_MODE (operands[n]));
  108.       xops[0] = stack_pointer_rtx;
  109.       xops[1] = gen_rtx (CONST_INT, VOIDmode,
  110.              GET_MODE_SIZE (GET_MODE (operands[n])));
  111.       output_asm_insn (op, operands + n);
  112.       output_asm_insn (AS2 (add%L0,%1,%0), xops);
  113.     }
  114.   else
  115.     output_asm_insn (op, operands + n);
  116.  
  117.   RET;
  118. }
  119.  
  120. /* Output assembler code to perform insn OP
  121.    with two stack operands, and output on the stack.
  122.  
  123.    REV is the assembler insn that does the same thing but
  124.    effectively interchanges the meanings of the two arguments.
  125.  
  126.    Somewhat counterintuitively, the "first" operand was pushed last.
  127.  
  128.    The output replaces either the top-of-stack or both of the arguments,
  129.    depending on whether the other argument is wanted after this insn.  */
  130.  
  131. static void
  132. output_asm_insn_double_reg_op (op, rev, insn)
  133.      char *op;
  134.      char *rev;
  135.      rtx insn;
  136. {
  137.   fputc ('\t', asm_out_file);
  138.   if (top_dead_p (insn))
  139.     {
  140.       /* Here we want the "reversed" insn, fsubr or fdivr.
  141.      But there is an assembler bug in all 80386 assemblers
  142.      which exchanges the meanings of fsubr and fsub, and of fdivr and fdiv!
  143.      So use the "unreversed" opcode (which will assemble into
  144.      the "reversed" insn).  */
  145.       rev = op;
  146.  
  147.       while (*rev && *rev != '%')
  148.     fputc (*rev++, asm_out_file);
  149.       /* fp_pop_level--; */
  150.  
  151.       fprintf (asm_out_file, AS2 (p,%sst,%sst(1)), RP, RP);
  152.     }
  153.   else
  154.     {
  155.       while (*op && *op != '%')
  156.     fputc (*op++, asm_out_file);
  157.       fprintf (asm_out_file,AS2 ( ,%sst(1),%sst), RP, RP);
  158.     }
  159.   putc ('\n', asm_out_file);
  160. }
  161.  
  162. /* Moves X to memory location 8 below stack pointer
  163.    and returns an RTX for that memory location.
  164.    X should be a register, in DFmode or SFmode.  */
  165.  
  166. static rtx
  167. via_memory (x)
  168.      rtx x;
  169. {
  170.   if (!REG_P (x))
  171.     abort ();
  172.   if (GET_MODE (x) == DFmode)
  173.     {
  174.       rtx xops[1];
  175.       xops[0] = gen_rtx (REG, SImode, REGNO (x) + 1);
  176.       output_asm_insn ("push%L0 %0", xops);
  177.     }
  178.   output_asm_insn ("push%L0 %0", &x);
  179. }
  180.  
  181. /* Output an insn to copy the SFmode value in fp0 to OPERAND
  182.    without clobbering fp0.  */
  183.  
  184. void
  185. fp_store_sf (target)
  186.      rtx target;
  187. {
  188.   if (REG_P (target))
  189.     {
  190.       rtx xoperands[3];
  191.       xoperands[0] = stack_pointer_rtx;
  192.       xoperands[1] = AT_SP (Pmode);
  193.       xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4);
  194.       output_asm_insn (AS2 (add%L0,%2,%0), xoperands);
  195.       output_asm_insn ("fst%S0 %1", xoperands);
  196.       output_asm_insn ("pop%L0 %0", &target);
  197.     }
  198.   else if (GET_CODE (target) == MEM)
  199.     output_asm_insn ("fst%S0 %0", &target);
  200. }
  201.  
  202. /* Output an insn to pop an SF value from fp0 into TARGET.
  203.    This destroys the value of fp0.  */
  204.  
  205. void
  206. fp_pop_sf (target)
  207.      rtx target;
  208. {
  209.   if (REG_P (target))
  210.     {
  211.       rtx xoperands[3];
  212.       xoperands[0] = stack_pointer_rtx;
  213.       xoperands[1] = AT_SP (Pmode);
  214.       xoperands[2] = gen_rtx (CONST_INT, VOIDmode, -4);
  215.       output_asm_insn (AS2 (add%L0,%2,%0), xoperands);
  216.       output_asm_insn ("fstp%S0 %1", xoperands);
  217.       output_asm_insn ("pop%L0 %0", &target);
  218.       /* fp_pop_level--; */
  219.     }
  220.   else if (GET_CODE (target) == MEM)
  221.     {
  222.       /* fp_pop_level--; */
  223.       output_asm_insn ("fstp%S0 %0", &target);
  224.     }
  225.   else abort ();
  226. }
  227.  
  228. /* Copy the top of the fpu stack into TARGET, without popping.  */
  229.  
  230. void
  231. fp_store_df (target)
  232.      rtx target;
  233. {
  234.   if (REG_P (target))
  235.     {
  236.       rtx xoperands[4];
  237.       xoperands[0] = stack_pointer_rtx;
  238.       xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1);
  239.       xoperands[2] = AT_SP (Pmode);
  240.       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8);
  241.       output_asm_insn (AS2 (add%L0,%3,%0), xoperands);
  242.       output_asm_insn ("fst%Q0 %2", xoperands);
  243.       output_asm_insn ("pop%L0 %0", &target);
  244.       output_asm_insn ("pop%L0 %1", xoperands);
  245.     }
  246.   else if (GET_CODE (target) == MEM)
  247.     output_asm_insn ("fst%Q0 %0", &target);
  248. }
  249.  
  250. /* Copy the top of the fpu stack into TARGET, with popping.  */
  251.  
  252. void
  253. fp_pop_df (target)
  254.      rtx target;
  255. {
  256.   if (REG_P (target))
  257.     {
  258.       rtx xoperands[4];
  259.       xoperands[0] = stack_pointer_rtx;
  260.       xoperands[1] = gen_rtx (REG, SImode, REGNO (target) + 1);
  261.       xoperands[2] = AT_SP (Pmode);
  262.       xoperands[3] = gen_rtx (CONST_INT, VOIDmode, -8);
  263.       output_asm_insn (AS2 (add%L0,%3,%0), xoperands);
  264.       /* fp_pop_level--; */
  265.       output_asm_insn ("fstp%Q0 %2", xoperands);
  266.       output_asm_insn ("pop%L0 %0", &target);
  267.       output_asm_insn ("pop%L0 %1", xoperands);
  268.     }
  269.   else if (GET_CODE (target) == MEM)
  270.     {
  271.       /* fp_pop_level--; */
  272.       output_asm_insn ("fstp%z0 %0", &target);
  273.     }
  274. }
  275.  
  276. #if 0
  277. /* Pop the fp stack, convert value to integer and store in TARGET.
  278.    TARGET may be memory or register, and may have QI, HI or SImode.  */
  279.  
  280. void
  281. fp_pop_int (target)
  282.      rtx target;
  283. {
  284.   if (REG_P (target) || GET_MODE (target) != SImode)
  285.     {
  286.       rtx xxops[2];
  287.       xxops[0] = stack_pointer_rtx;
  288.       xxops[1] = gen_rtx (CONST_INT, VOIDmode, 4);
  289.       output_asm_insn (AS2 (sub%L0,%1,%0), xxops);
  290.       xxops[0] = AT_SP (Pmode);
  291.       /* fp_pop_level--; */
  292.       output_asm_insn ("fistp%L0 %0", xxops);
  293.       output_asm_insn ("pop%L0 %0", &target);
  294.     }
  295.   else if (GET_CODE (target) == MEM)
  296.     {
  297.       /* fp_pop_level--; */
  298.       output_asm_insn ("fistp%L0 %0", &target);
  299.     }
  300.   else abort ();
  301. }
  302. #endif
  303.  
  304. /* Push the SFmode value X onto the fpu stack.  */
  305.  
  306. void
  307. fp_push_sf (x)
  308.      rtx x;
  309. {
  310.   /* fp_pop_level++; */
  311.   if (REG_P (x))
  312.     {
  313.       rtx xoperands[2];
  314.       rtx xfops[3];
  315.       output_asm_insn ("push%L0 %0", &x);
  316.       xfops[0] = AT_SP (Pmode);
  317.       xfops[2] = gen_rtx (CONST_INT, VOIDmode, 4);
  318.       xfops[1] = stack_pointer_rtx;
  319.       output_asm_insn ("fld%S0 %0 \n\tadd%L0 %2,%1", xfops);
  320.     }
  321.   else
  322.     output_asm_insn ("fld%S0 %0", &x);
  323. }
  324.  
  325. /* Push the DFmode value X onto the fpu stack.  */
  326.  
  327. void
  328. fp_push_df (x)
  329.      rtx x;
  330. {
  331.   /* fp_pop_level++; */
  332.  
  333.   if (REG_P (x))
  334.     {
  335.       rtx xoperands[2];
  336.       rtx xfops[3];
  337.       xoperands[0] = x;
  338.       xoperands[1] = gen_rtx (REG, SImode, REGNO (x) + 1);
  339.       output_asm_insn ("push%L0 %1", xoperands);
  340.       output_asm_insn ("push%L0 %0", xoperands);
  341.       xfops[0] = AT_SP (Pmode);
  342.       xfops[2] = gen_rtx (CONST_INT, VOIDmode, 8);
  343.       xfops[1] = stack_pointer_rtx;
  344.       output_asm_insn ("fld%Q0 %0 \n\tadd%L0 %2,%1", xfops);
  345.     }
  346.   else if (GET_CODE (x) == MEM)
  347.     output_asm_insn ("fld%Q0 %0", &x);
  348. }
  349.  
  350. static char *output_move_const_single ();
  351.  
  352. static char *
  353. singlemove_string (operands)
  354.      rtx *operands;
  355. {
  356.   rtx x;
  357.   if (GET_CODE (operands[0]) == MEM
  358.       && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)
  359.     {
  360.       if (XEXP (x, 0) != stack_pointer_rtx)
  361.     abort ();
  362.       return "push%L0 %1";
  363.     }
  364.   else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  365.     {
  366.       return output_move_const_single (operands);
  367.     }
  368.   else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
  369.     return AS2 (mov%L0,%1,%0);
  370.   else if (CONSTANT_P (operands[1]))
  371.     return AS2 (mov%L0,%1,%0);
  372.   else
  373.     {
  374.       output_asm_insn ("push%L0 %1", operands);
  375.       return "pop%L0 %0";
  376.     }
  377. }
  378.  
  379. /* Return a REG that occurs in ADDR with coefficient 1.
  380.    ADDR can be effectively incremented by incrementing REG.  */
  381.  
  382. static rtx
  383. find_addr_reg (addr)
  384.      rtx addr;
  385. {
  386.   while (GET_CODE (addr) == PLUS)
  387.     {
  388.       if (GET_CODE (XEXP (addr, 0)) == REG)
  389.     addr = XEXP (addr, 0);
  390.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  391.     addr = XEXP (addr, 1);
  392.       else if (CONSTANT_P (XEXP (addr, 0)))
  393.     addr = XEXP (addr, 1);
  394.       else if (CONSTANT_P (XEXP (addr, 1)))
  395.     addr = XEXP (addr, 0);
  396.       else
  397.     abort ();
  398.     }
  399.   if (GET_CODE (addr) == REG)
  400.     return addr;
  401.   abort ();
  402. }
  403.  
  404. /* Output an insn to add the constant N to the register X.  */
  405.  
  406. static void
  407. asm_add (n, x)
  408.      int n;
  409.      rtx x;
  410. {
  411.   rtx xops[2];
  412.   xops[1] = x;
  413.   if (n < 0)
  414.     {
  415.       xops[0] = gen_rtx (CONST_INT, VOIDmode, -n);
  416.       output_asm_insn (AS2 (sub%L0,%0,%1), xops);
  417.     }
  418.   else if (n > 0)
  419.     {
  420.       xops[0] = gen_rtx (CONST_INT, VOIDmode, n);
  421.       output_asm_insn (AS2 (add%L0,%0,%1), xops);
  422.     }
  423. }
  424.  
  425. /* Output assembler code to perform a doubleword move insn
  426.    with operands OPERANDS.  */
  427.  
  428. char *
  429. output_move_double (operands)
  430.      rtx *operands;
  431. {
  432.   enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  433.   rtx latehalf[2];
  434.   rtx addreg0 = 0, addreg1 = 0;
  435.  
  436.   /* First classify both operands.  */
  437.  
  438.   if (REG_P (operands[0]))
  439.     optype0 = REGOP;
  440.   else if (offsettable_memref_p (operands[0]))
  441.     optype0 = OFFSOP;
  442.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  443.     optype0 = POPOP;
  444.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  445.     optype0 = PUSHOP;
  446.   else if (GET_CODE (operands[0]) == MEM)
  447.     optype0 = MEMOP;
  448.   else
  449.     optype0 = RNDOP;
  450.  
  451.   if (REG_P (operands[1]))
  452.     optype1 = REGOP;
  453.   else if (CONSTANT_P (operands[1])
  454.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  455.     optype1 = CNSTOP;
  456.   else if (offsettable_memref_p (operands[1]))
  457.     optype1 = OFFSOP;
  458.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  459.     optype1 = POPOP;
  460.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  461.     optype1 = PUSHOP;
  462.   else if (GET_CODE (operands[1]) == MEM)
  463.     optype1 = MEMOP;
  464.   else
  465.     optype1 = RNDOP;
  466.  
  467.   /* Check for the cases that the operand constraints are not
  468.      supposed to allow to happen.  Abort if we get one,
  469.      because generating code for these cases is painful.  */
  470.  
  471.   if (optype0 == RNDOP || optype1 == RNDOP)
  472.     abort ();
  473.  
  474.   /* If one operand is decrementing and one is incrementing
  475.      decrement the former register explicitly
  476.      and change that operand into ordinary indexing.  */
  477.  
  478.   if (optype0 == PUSHOP && optype1 == POPOP)
  479.     {
  480.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  481.       asm_add (-8, operands[0]);
  482.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  483.       optype0 = OFFSOP;
  484.     }
  485.   if (optype0 == POPOP && optype1 == PUSHOP)
  486.     {
  487.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  488.       asm_add (-8, operands[1]);
  489.       operands[1] = gen_rtx (MEM, DImode, operands[1]);
  490.       optype1 = OFFSOP;
  491.     }
  492.  
  493.   /* If an operand is an unoffsettable memory ref, find a register
  494.      we can increment temporarily to make it refer to the second word.  */
  495.  
  496.   if (optype0 == MEMOP)
  497.     addreg0 = find_addr_reg (XEXP (operands[0], 0));
  498.  
  499.   if (optype1 == MEMOP)
  500.     addreg1 = find_addr_reg (XEXP (operands[1], 0));
  501.  
  502.   /* Ok, we can do one word at a time.
  503.      Normally we do the low-numbered word first,
  504.      but if either operand is autodecrementing then we
  505.      do the high-numbered word first.
  506.  
  507.      In either case, set up in LATEHALF the operands to use
  508.      for the high-numbered word and in some cases alter the
  509.      operands in OPERANDS to be suitable for the low-numbered word.  */
  510.  
  511.   if (optype0 == REGOP)
  512.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  513.   else if (optype0 == OFFSOP)
  514.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  515.   else
  516.     latehalf[0] = operands[0];
  517.  
  518.   if (optype1 == REGOP)
  519.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  520.   else if (optype1 == OFFSOP)
  521.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  522.   else if (optype1 == CNSTOP)
  523.     {
  524.       if (CONSTANT_P (operands[1]))
  525.     latehalf[1] = const0_rtx;
  526.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  527.     {
  528.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
  529.                  CONST_DOUBLE_HIGH (operands[1]));
  530.       operands[1] = gen_rtx (CONST_INT, VOIDmode,
  531.                  CONST_DOUBLE_LOW (operands[1]));
  532.     }
  533.     }
  534.   else
  535.     latehalf[1] = operands[1];
  536.  
  537.   /* If insn is effectively movd N (sp),-(sp) then we will do the
  538.      high word first.  We should use the adjusted operand 1 (which is N+4 (sp))
  539.      for the low word as well, to compensate for the first decrement of sp.  */
  540.   if (optype0 == PUSHOP
  541.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  542.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  543.     operands[1] = latehalf[1];
  544.  
  545.   /* If one or both operands autodecrementing,
  546.      do the two words, high-numbered first.  */
  547.  
  548.   /* Likewise,  the first move would clobber the source of the second one,
  549.      do them in the other order.  This happens only for registers;
  550.      such overlap can't happen in memory unless the user explicitly
  551.      sets it up, and that is an undefined circumstance.  */
  552.  
  553.   if (optype0 == PUSHOP || optype1 == PUSHOP
  554.       || (optype0 == REGOP && optype1 == REGOP
  555.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  556.     {
  557.       /* Make any unoffsettable addresses point at high-numbered word.  */
  558.       if (addreg0)
  559.     asm_add (4, addreg0);
  560.       if (addreg1)
  561.     asm_add (4, addreg1);
  562.  
  563.       /* Do that word.  */
  564.       output_asm_insn (singlemove_string (latehalf), latehalf);
  565.  
  566.       /* Undo the adds we just did.  */
  567.       if (addreg0)
  568.          asm_add (-4, addreg0);
  569.       if (addreg1)
  570.     asm_add (-4, addreg1);
  571.  
  572.       /* Do low-numbered word.  */
  573.       return singlemove_string (operands);
  574.     }
  575.  
  576.   /* Normal case: do the two words, low-numbered first.  */
  577.  
  578.   output_asm_insn (singlemove_string (operands), operands);
  579.  
  580.   /* Make any unoffsettable addresses point at high-numbered word.  */
  581.   if (addreg0)
  582.     asm_add (4, addreg0);
  583.   if (addreg1)
  584.     asm_add (4, addreg1);
  585.  
  586.   /* Do that word.  */
  587.   output_asm_insn (singlemove_string (latehalf), latehalf);
  588.  
  589.   /* Undo the adds we just did.  */
  590.   if (addreg0)
  591.     asm_add (-4, addreg0);
  592.   if (addreg1)
  593.     asm_add (-4, addreg1);
  594.  
  595.   return "";
  596. }
  597.  
  598. int
  599. standard_80387_constant_p (x)
  600.      rtx x;
  601. {
  602.   union { double d; int i[2];} u;
  603.   register double d;
  604.   u.i[0] = XINT (x, 0);
  605.   u.i[1] = XINT (x, 1);
  606.   d = u.d;
  607.  
  608.   if (d == 0)
  609.     return 1;
  610.   if (d == 1)
  611.     return 2;
  612.   /* Note that on the 80387, other constants, such as pi,
  613.      are much slower to load as standard constants
  614.      than to load from doubles in memory!  */
  615.  
  616.   return 0;
  617. }
  618.  
  619. static char *
  620. output_move_const_double (operands)
  621.      rtx *operands;
  622. {
  623.   if (FP_REG_P (operands[0]))
  624.     {
  625.       int conval = standard_80387_constant_p (operands[1]);
  626.  
  627.       /* fp_pop_level++; */
  628.       if (conval == 1)
  629.     return "fldz";
  630.       if (conval == 2)
  631.     return "fld1";
  632.       /* fp_pop_level--; */
  633.     }
  634.  
  635.   output_move_double (operands);
  636. }
  637.  
  638.  
  639. static char *
  640. output_move_const_single (operands)
  641.      rtx *operands;
  642. {
  643.   if (FP_REG_P (operands[0]))
  644.     {
  645.       int conval = standard_80387_constant_p (operands[1]);
  646.  
  647.       /* fp_pop_level++; */
  648.       if (conval == 1)
  649.     return "fldz";
  650.       if (conval == 2)
  651.     return "fld1";
  652.       /* fp_pop_level--; */
  653.     }
  654.   if (GET_CODE (operands[1]) == CONST_DOUBLE)
  655.     {
  656.       union { int i[2]; double d;} u1;
  657.       union { int i; float f;} u2;
  658.       u1.i[0] = CONST_DOUBLE_LOW (operands[1]);
  659.       u1.i[1] = CONST_DOUBLE_HIGH (operands[1]);
  660.       u2.f = u1.d;
  661.       operands[1] = gen_rtx (CONST_INT, VOIDmode, u2.i);
  662.     }
  663.   return singlemove_string (operands);
  664. }
  665.  
  666. /* Output an insn to move an SF value from FROM to TO.
  667.    The kinds of operands are not restricted
  668.    except that they may not both be in memory.  */
  669.  
  670. void
  671. output_movsf (to, from)
  672.      rtx from, to;
  673. {
  674.   rtx xops[2];
  675.   xops[0] = to;
  676.   xops[1] = from;
  677.   if (FP_REG_P (from) || FP_REG_P (to))
  678.     {
  679.       from = xops[1];
  680.     }
  681.  
  682.   if (FP_REG_P (from))
  683.     {
  684. #if 0
  685.     {
  686.       if (REGNO (from) != REGNO (to))
  687.         {
  688.           output_asm_insn ("fld%S0 %1 \n\tfstp%S0 %0", xops);
  689.         }
  690.     }
  691.       else
  692. #endif
  693.  
  694.       if (! FP_REG_P (to))
  695.     fp_pop_sf (to);
  696.     }
  697.   else if (FP_REG_P (to))
  698.     fp_push_sf (from);
  699.   else
  700.     output_asm_insn (singlemove_string (xops), xops);
  701. }
  702.  
  703. /* Output an insn to move a DF value from FROM to TO.
  704.    The kinds of operands are not restricted
  705.    except that they may not both be in memory.  */
  706.  
  707. void
  708. output_movdf (to, from)
  709.      rtx from, to;
  710. {
  711.   rtx xops[2];
  712.   xops[0] = to;
  713.   xops[1] = from;
  714.   if (FP_REG_P (from) || FP_REG_P (to))
  715.     {
  716.       from = xops[1];
  717.       to = xops[0];
  718.     }
  719.   if (FP_REG_P (from))
  720.     {
  721. #if 0
  722.     {
  723.       if (REGNO (from) != REGNO (to))
  724.         abort ();
  725. /*        output_asm_insn ("fld%Q0 %1 \n\t fstp%Q0 %0", xops);*/
  726.     }
  727.       else
  728.     {
  729. #endif
  730.       if (! FP_REG_P (to))
  731.     fp_pop_df (to);
  732.     }
  733.   else if (FP_REG_P (to))
  734.     fp_push_df (from);
  735.   else
  736.     output_asm_insn (output_move_double (xops), xops);
  737. }
  738.  
  739. /* does move of FROM to TO where the mode is the minimum of the
  740. two */
  741.  
  742. static void
  743. output_movf (to, from)
  744.      rtx to, from;
  745. {
  746.   if (GET_MODE (from) == SFmode || GET_MODE (to) == SFmode)
  747.     output_movsf (to, from);
  748.   else
  749.     output_movdf (to, from);
  750. }
  751.  
  752. /* Return the best assembler insn template
  753.    for moving operands[1] into operands[0] as a fullword.  */
  754.  
  755. void
  756. function_prologue (file, size)
  757.      FILE *file;
  758.      int size;
  759. {
  760.   register int regno;
  761.   int nregs, limit;
  762.   rtx xops[4];
  763.   extern int frame_pointer_needed;
  764.  
  765.   /* fp_pop_level = 0; */
  766.   xops[0] = stack_pointer_rtx;
  767.   xops[1] = frame_pointer_rtx;
  768.   xops[2] = gen_rtx (CONST_INT, VOIDmode, size);
  769.   if (frame_pointer_needed)
  770.     {
  771.       output_asm_insn ("push%L0 %1", xops);
  772.       output_asm_insn (AS2 (mov%L0,%0,%1), xops);
  773.       if (size)
  774.     output_asm_insn (AS2 (sub%L0,%2,%0), xops);
  775.     }
  776.  
  777.   /* Note If use enter it is NOT reversed args.
  778.      This one is not reversed from intel!!
  779.      I think enter is slower.  Also sdb doesn't like it.
  780.      But if you want it the code is:
  781.      {
  782.      xops[3] = const0_rtx;
  783.      output_asm_insn ("enter %2,%3", xops);
  784.      }
  785.      */
  786.   nregs = 0;
  787.   limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
  788.   for (regno = limit - 1; regno >= 0; regno--)
  789.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  790.       {
  791.     fprintf (file, "\tpush%s %se%s\n", L_SIZE, RP, hi_reg_name[regno]);
  792.       }
  793. }
  794.  
  795. void
  796. function_epilogue (file, size)
  797.      FILE *file;
  798.      int size;
  799. {
  800.   register int regno;
  801.   register int nregs, limit;
  802.   int assure_sp_pos;
  803.   extern int frame_pointer_needed;
  804.   extern int current_function_pops_args;
  805.   extern int current_function_args_size;
  806.   limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
  807.   nregs = 0;
  808.  
  809.  
  810.   for (regno = (limit -1); regno >= 0; regno--)
  811.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  812.       nregs++;
  813.  
  814.   /* sp is often  unreliable so we must go off the frame pointer,
  815.    */
  816.  
  817.   if (nregs && frame_pointer_needed)
  818.     {
  819.       rtx xops[2];
  820.       xops[0] = adj_offsettable_operand (AT_BP (Pmode),
  821.                      -size -(nregs*(UNITS_PER_WORD)));
  822.       xops[1] = stack_pointer_rtx;
  823.       output_asm_insn (AS2 (lea%L0,%0,%1), xops);
  824.     }
  825.   for (regno = 0; regno < limit; regno++)
  826.     {
  827.       if (regs_ever_live[regno] && ! call_used_regs[regno])
  828.     {
  829.       fprintf (file, "\tpop%s ", L_SIZE);
  830.       fprintf (file, "%se%s\n", RP, hi_reg_name[regno]);
  831.     }
  832.     }
  833.  
  834.   if (frame_pointer_needed)
  835.     fprintf (file, "\tleave\n");
  836.   if (current_function_pops_args && current_function_args_size)
  837.     fprintf (file, "\tret %s%d\n", IP,
  838.          (current_function_args_size
  839.           + (current_function_returns_struct ? 4 : 0)));
  840.   else if (current_function_returns_struct)
  841.     fprintf (file, "\tret %s4\n", IP);
  842.   else
  843.     fprintf (file, "\tret\n");
  844. }
  845.  
  846. int
  847. hard_regno_mode_ok (regno, mode)
  848.      int regno;
  849.      enum machine_mode mode;
  850. {
  851.   return
  852.     (regno < 2 ? 1
  853.      /* Used to reject floating modes here */
  854.      : regno < 4 ? 1
  855.      : regno >= 8 ? mode == DFmode || mode == SFmode
  856.      : mode != QImode);
  857. }
  858.  
  859. /* Print the name of a register based on its machine mode and number.
  860.    If CODE is 'w', pretend the mode is HImode.
  861.    If CODE is 'b', pretend the mode is QImode.  */
  862.  
  863. #define PRINT_REG(X, CODE, FILE) \
  864.   do { fprintf (FILE, "%s", RP);            \
  865.        switch ((CODE == 'w' ? 2             \
  866.         : CODE == 'b' ? 1            \
  867.         : GET_MODE_SIZE (GET_MODE (X))))    \
  868.      {                        \
  869.      case 4:                    \
  870.      case 8:                    \
  871.        if (!FP_REG_P (X)) fputs ("e", FILE);    \
  872.      case 2:                    \
  873.        fputs (hi_reg_name[REGNO (X)], FILE);    \
  874.        break;                    \
  875.      case 1:                    \
  876.        fputs (qi_reg_name[REGNO (X)], FILE);    \
  877.      }                        \
  878.      } while (0)
  879.  
  880. /* Meaning of CODE:
  881.    f -- float insn (print a CONST_DOUBLE as a float rather than in hex).
  882.    L,W,B,Q,S -- print the opcode suffix for specified size of operand.
  883.    R -- print the prefix for register names.
  884.    z -- print the opcode suffix for the size of the current operand.
  885.    * -- print a star (in certain assembler syntax)
  886.    w -- print the operand as if it's a "word" (HImode) even if it isn't.
  887.    c -- don't print special prefixes before constant operands.
  888. */
  889.  
  890. void
  891. print_operand (file, x, code)
  892.      FILE *file;
  893.      rtx x;
  894.      int code;
  895. {
  896.   if (code)
  897.     {
  898.       switch (code)
  899.     {
  900.     case '*':
  901.       if (USE_STAR)
  902.         putc ('*', file);
  903.       return;
  904.  
  905.     case 'L':
  906.       PUT_OP_SIZE (code, 'l', file);
  907.       return;
  908.  
  909.     case 'W':
  910.       PUT_OP_SIZE (code, 'w', file);
  911.       return;
  912.  
  913.     case 'B':
  914.       PUT_OP_SIZE (code, 'b', file);
  915.       return;
  916.  
  917.     case 'Q':
  918.       PUT_OP_SIZE (code, 'l', file);
  919.       return;
  920.  
  921.     case 'S':
  922.       PUT_OP_SIZE (code, 's', file);
  923.       return;
  924.  
  925.     case 'R':
  926.       fprintf (file, "%s", RP);
  927.       return;
  928.  
  929.     case 'z':
  930.       /* this is the size of op from size of operand */
  931.       switch (GET_MODE_SIZE (GET_MODE (x)))
  932.         {
  933.         case 2:
  934.           PUT_OP_SIZE ('W', 'w', file);
  935.           return;
  936.         case 4:
  937.           if (GET_MODE (x) == SFmode)
  938.         {
  939.           PUT_OP_SIZE ('S', 's', file);
  940.           return;
  941.         }
  942.           else
  943.         PUT_OP_SIZE ('L', 'l', file);
  944.           return;
  945.         case 8:
  946.           if (!FP_REG_P (x)) PUT_OP_SIZE ('Q', 'l', file);
  947.           return;
  948.         case 1:
  949.           PUT_OP_SIZE ('B', 'b', file);
  950.           return;
  951.         }
  952.     }
  953.     }
  954.   if (GET_CODE (x) == REG)
  955.     {
  956.       PRINT_REG (x, code, file);
  957.     }
  958.   else if (GET_CODE (x) == MEM)
  959.     {
  960.       PRINT_PTR (x, file);
  961.       if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
  962.     output_addr_const (file, XEXP (x, 0));
  963.       else
  964.     output_address (XEXP (x, 0));
  965.     }
  966.   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
  967.     {
  968.       union { double d; int i[2]; } u;
  969.       union { float f; int i; } u1;
  970.       u.i[0] = CONST_DOUBLE_LOW (x);
  971.       u.i[1] = CONST_DOUBLE_HIGH (x);
  972.       u1.f = u.d;
  973.       if (code == 'f')
  974.         fprintf (file, "%.22e", u1.f);
  975.       else
  976.         {
  977.       PRINT_IMMED_PREFIX (file);
  978.       fprintf (file, "0x%x", u1.i);
  979.     }
  980.     }
  981.   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
  982.     {
  983.       union { double d; int i[2]; } u;
  984.       u.i[0] = CONST_DOUBLE_LOW (x);
  985.       u.i[1] = CONST_DOUBLE_HIGH (x);
  986.       fprintf (file, "%.22e", u.d);
  987.     }
  988.   else 
  989.     {
  990.       if (code != 'c')
  991.     {
  992.       if (GET_CODE (x) == CONST_INT)
  993.         PRINT_IMMED_PREFIX (file);
  994.       else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF)
  995.         PRINT_OFFSET_PREFIX (file);
  996.     }
  997.       output_addr_const (file, x);
  998.     }
  999. }
  1000.  
  1001. /* Print a memory operand whose address is ADDR.  */
  1002.  
  1003. void
  1004. print_operand_address (file, addr)
  1005.      FILE *file;
  1006.      register rtx addr;
  1007. {
  1008.   register rtx reg1, reg2, breg, ireg;
  1009.   rtx offset;
  1010.  
  1011.   switch (GET_CODE (addr))
  1012.     {
  1013.     case REG:
  1014.       ADDR_BEG (file);
  1015.       fprintf (file, "%se", RP);
  1016.       fputs (hi_reg_name[REGNO (addr)], file);
  1017.       ADDR_END (file);
  1018.       break;
  1019.  
  1020.     case PLUS:
  1021.       reg1 = 0;
  1022.       reg2 = 0;
  1023.       ireg = 0;
  1024.       breg = 0;
  1025.       offset = 0;
  1026.       if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
  1027.     {
  1028.       offset = XEXP (addr, 0);
  1029.       addr = XEXP (addr, 1);
  1030.     }
  1031.       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
  1032.     {
  1033.       offset = XEXP (addr, 1);
  1034.       addr = XEXP (addr, 0);
  1035.     }
  1036.       if (GET_CODE (addr) != PLUS) ;
  1037.       else if (GET_CODE (XEXP (addr, 0)) == MULT)
  1038.     {
  1039.       reg1 = XEXP (addr, 0);
  1040.       addr = XEXP (addr, 1);
  1041.     }
  1042.       else if (GET_CODE (XEXP (addr, 1)) == MULT)
  1043.     {
  1044.       reg1 = XEXP (addr, 1);
  1045.       addr = XEXP (addr, 0);
  1046.     }
  1047.       else if (GET_CODE (XEXP (addr, 0)) == REG)
  1048.     {
  1049.       reg1 = XEXP (addr, 0);
  1050.       addr = XEXP (addr, 1);
  1051.     }
  1052.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  1053.     {
  1054.       reg1 = XEXP (addr, 1);
  1055.       addr = XEXP (addr, 0);
  1056.     }
  1057.       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
  1058.     {
  1059.       if (reg1 == 0) reg1 = addr;
  1060.       else reg2 = addr;
  1061.       addr = 0;
  1062.     }
  1063.       if (offset != 0)
  1064.     {
  1065.       if (addr != 0) abort ();
  1066.       addr = offset;
  1067.     }
  1068.       if ((reg1 && GET_CODE (reg1) == MULT)
  1069.       || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
  1070.     {
  1071.       breg = reg2;
  1072.       ireg = reg1;
  1073.     }
  1074.       else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
  1075.     {
  1076.       breg = reg1;
  1077.       ireg = reg2;
  1078.     }
  1079.  
  1080.       if (ireg != 0 || breg != 0)
  1081.     {
  1082.       int scale = 1;
  1083.  
  1084.       if (addr != 0)
  1085.         {
  1086.           if (GET_CODE (addr) == LABEL_REF)
  1087.         output_asm_label (addr);
  1088.           else
  1089.         output_addr_const (file, addr);
  1090.         }
  1091.  
  1092.         if (ireg != 0 && GET_CODE (ireg) == MULT)
  1093.         {
  1094.           scale = INTVAL (XEXP (ireg, 1));
  1095.           ireg = XEXP (ireg, 0);
  1096.         }
  1097.       /* output breg+ireg*scale */
  1098.       PRINT_B_I_S (breg, ireg, scale, file);
  1099.       break;
  1100.     }
  1101.  
  1102.     case MULT:
  1103.       {
  1104.     int scale;
  1105.     if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
  1106.       {
  1107.         scale = INTVAL (XEXP (addr, 0));
  1108.         ireg = XEXP (addr, 1);
  1109.       }
  1110.     else
  1111.       {
  1112.         scale = INTVAL (XEXP (addr, 1));
  1113.         ireg = XEXP (addr, 0);
  1114.       }
  1115.     output_addr_const (file, const0_rtx);
  1116.     PRINT_B_I_S ((rtx) 0, ireg, scale, file);
  1117.       }
  1118.       break;
  1119.  
  1120.     default:
  1121.       if (GET_CODE (addr) == CONST_INT
  1122.       && INTVAL (addr) < 0x8000
  1123.       && INTVAL (addr) >= -0x8000)
  1124.     fprintf (file, "%d", INTVAL (addr));
  1125.       else
  1126.     output_addr_const (file, addr);
  1127.     }
  1128. }
  1129.  
  1130. /* Set the cc_status for the results of an insn whose pattern is EXP.
  1131.    On the 80386, we assume that only test and compare insns, as well
  1132.    as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT, LSHIFT,
  1133.    ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully.
  1134.    Also, we assume that jumps and moves don't affect the condition codes.
  1135.    All else, clobbers the condition codes, by assumption.
  1136.  
  1137.    We assume that ALL add, minus, etc. instructions effect the condition
  1138.    codes.  This MUST be consistent with i386.md.  */
  1139.  
  1140. notice_update_cc (exp)
  1141.      rtx exp;
  1142. {
  1143.   if (GET_CODE (exp) == SET)
  1144.     {
  1145.       /* Jumps do not alter the cc's.  */
  1146.       if (SET_DEST (exp) == pc_rtx)
  1147.     return;
  1148.       /* Moving register or memory into a register:
  1149.      it doesn't alter the cc's, but it might invalidate
  1150.      the RTX's which we remember the cc's came from.
  1151.      (Note that moving a constant 0 or 1 MAY set the cc's).  */
  1152.       if (REG_P (SET_DEST (exp))
  1153.       && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM))
  1154.     {
  1155.       if (cc_status.value1
  1156.           && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
  1157.         cc_status.value1 = 0;
  1158.       if (cc_status.value2
  1159.           && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
  1160.         cc_status.value2 = 0;
  1161.       return;
  1162.     }
  1163.       /* Moving register into memory doesn't alter the cc's.
  1164.      It may invalidate the RTX's which we remember the cc's came from.  */
  1165.       if (GET_CODE (SET_DEST (exp)) == MEM && REG_P (SET_SRC (exp)))
  1166.     {
  1167.       if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM)
  1168.         cc_status.value1 = 0;
  1169.       if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM)
  1170.         cc_status.value2 = 0;
  1171.       return;
  1172.     }
  1173.       /* Function calls clobber the cc's.  */
  1174.       else if (GET_CODE (SET_SRC (exp)) == CALL)
  1175.     {
  1176.       CC_STATUS_INIT;
  1177.       return;
  1178.     }
  1179.       /* Tests and compares set the cc's in predictable ways.  */
  1180.       else if (SET_DEST (exp) == cc0_rtx)
  1181.     {
  1182.       CC_STATUS_INIT;
  1183.       cc_status.value1 = SET_SRC (exp);
  1184.       return;
  1185.     }
  1186.       /* Certain instructions effect the condition codes. */
  1187.       else if (GET_MODE (SET_SRC (exp)) == SImode
  1188.            || GET_MODE (SET_SRC (exp)) == HImode
  1189.            || GET_MODE (SET_SRC (exp)) == QImode)
  1190.     switch (GET_CODE (SET_SRC (exp)))
  1191.       {
  1192.       case ASHIFTRT: case LSHIFTRT:
  1193.       case ASHIFT: case LSHIFT:
  1194.         /* Shifts on the 386 don't set the condition codes if the
  1195.            shift count is zero. */
  1196.         if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
  1197.           {
  1198.         CC_STATUS_INIT;
  1199.         break;
  1200.           }
  1201.         /* We assume that the CONST_INT is non-zero (this rtx would
  1202.            have been deleted if it were zero. */
  1203.  
  1204.       case PLUS: case MINUS: case NEG:
  1205.       case AND: case IOR: case XOR:
  1206.         cc_status.flags = CC_NO_OVERFLOW;
  1207.         cc_status.value1 = SET_SRC (exp);
  1208.         cc_status.value2 = SET_DEST (exp);
  1209.         break;
  1210.  
  1211.       default:
  1212.         CC_STATUS_INIT;
  1213.       }
  1214.       else
  1215.     {
  1216.       CC_STATUS_INIT;
  1217.     }
  1218.     }
  1219.   else if (GET_CODE (exp) == PARALLEL
  1220.        && GET_CODE (XVECEXP (exp, 0, 0)) == SET)
  1221.     {
  1222.       if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
  1223.     return;
  1224.       if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
  1225.     {
  1226.       CC_STATUS_INIT;
  1227.       cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
  1228.       return;
  1229.     }
  1230.       CC_STATUS_INIT;
  1231.     }
  1232.   else
  1233.     {
  1234.       CC_STATUS_INIT;
  1235.     }
  1236. }
  1237.  
  1238. /* Nonzero if the top of the fpu stack dies in this insn.  */
  1239.  
  1240. int
  1241. top_dead_p (insn)
  1242.      rtx insn;
  1243. {
  1244.   extern int optimize;
  1245.   if (optimize)
  1246.     return (find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG)
  1247.         || find_regno_note (insn, REG_DEAD, FIRST_FLOAT_REG + 1));
  1248.  
  1249.   if (GET_CODE (insn) == CALL_INSN)
  1250.     return call_top_dead_p (insn);
  1251.  
  1252.   return fp_top_dead_p1 (insn);
  1253. }
  1254.  
  1255. /* Following is used after a call_value insn
  1256.    if obey_regdecls there will not be the REG_DEAD notes
  1257.    to go by (there won't be any cross jumping to worry about
  1258.    either), and we depend on seeing if the FP_TOP is used
  1259.    in the next two insn's.  Otherwise we depend on the
  1260.    REG_DEAD notes.
  1261.    */
  1262.  
  1263. static int
  1264. call_top_dead_p (insn)
  1265.      rtx insn;
  1266. {
  1267.   int i;
  1268.   for (i = 0; i < 3; i++)
  1269.     {
  1270.       insn = NEXT_INSN (insn);
  1271.       if (insn == 0)
  1272.     return 1;
  1273.       if (GET_CODE (insn) == NOTE || GET_CODE (insn) == CODE_LABEL)
  1274.     continue;
  1275.       if (GET_CODE (insn) == BARRIER)
  1276.     abort ();
  1277.       if (GET_CODE (PATTERN (insn)) == SET
  1278.       && SET_DEST (PATTERN (insn)) != stack_pointer_rtx)
  1279.     return (!(mentions_fp_top (SET_SRC (PATTERN (insn)))));
  1280.       if (GET_CODE (PATTERN (insn)) == CALL)
  1281.     return 1;
  1282.       if (GET_CODE (PATTERN (insn)) == USE)
  1283.     return (! FP_REG_P (XEXP (PATTERN (insn), 0)));
  1284.     }
  1285.   return 1;
  1286. }
  1287.  
  1288. /* Return 1 if current val of fpu top-of-stack appears unused
  1289.    in rest of this basic block.  */
  1290.  
  1291. static int
  1292. fp_top_dead_p1 (insn)
  1293.      rtx insn;
  1294. {
  1295.   for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
  1296.     {
  1297.       switch (GET_CODE (insn))
  1298.     {
  1299.     case CALL_INSN:
  1300.       /* Function calls clobber this value, so it's dead.  */
  1301.     case JUMP_INSN:
  1302.     case CODE_LABEL:
  1303.       return 1;
  1304.  
  1305.     case INSN:
  1306.       if (GET_CODE (PATTERN (insn)) == SET)
  1307.         {
  1308.           if ((mentions_fp_top (SET_SRC (PATTERN (insn)))))
  1309.         return 0;
  1310.           else if (FP_REG_P (SET_DEST (PATTERN (insn))))
  1311.         return 1;
  1312.         }
  1313.       else if (mentions_fp_top (PATTERN (insn)))
  1314.         return 0;
  1315.       break;
  1316.     }
  1317.     }
  1318.   return 1;
  1319. }
  1320.  
  1321. /* Return 1 if X involves an FPU register.  */
  1322.  
  1323. static int
  1324. mentions_fp_top (x)
  1325.      rtx x;
  1326. {
  1327.   register RTX_CODE code;
  1328.  
  1329.   code = GET_CODE (x);
  1330.   switch (code)
  1331.     {
  1332.     case LABEL_REF:
  1333.     case SYMBOL_REF:
  1334.     case CONST_INT:
  1335.     case CONST:
  1336.     case CC0:
  1337.     case PC:
  1338.     case CLOBBER:
  1339.     case MEM:
  1340.       return 0;
  1341.  
  1342.     case REG:
  1343.       return FP_REGNO_P (REGNO (x));
  1344.     }
  1345.  
  1346.   /* Recursively scan the operands of this expression.  */
  1347.   {
  1348.     register char *fmt = GET_RTX_FORMAT (code);
  1349.     register int i;
  1350.  
  1351.     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
  1352.       {
  1353.     if (fmt[i] == 'e')
  1354.       {
  1355.         if (mentions_fp_top (XEXP (x, i)))
  1356.           return 1;
  1357.       }
  1358.     if (fmt[i] == 'E')
  1359.       {
  1360.         register int j;
  1361.         for (j = 0; j < XVECLEN (x, i); j++)
  1362.           if (mentions_fp_top (XVECEXP (x, i, j)))
  1363.         return 1;
  1364.       }
  1365.       }
  1366.   }
  1367.   return 0;
  1368. }
  1369.  
  1370. /* Some asm-dependent functions. */
  1371.  
  1372. #ifdef MASM
  1373. #include "masm386.c"
  1374. #endif
  1375.